#include "ShaderLib.h"
#include "ShaderChunk.h"
#include "UniformsLib.h"

POCELAIN_NAMESPACE_BEGIN

#define GET_UNIFORMS_LIB(name) \
    UniformsLib::getUniforms(#name)

#define GET_SHADERCHUNK_SOURCE(name) \
    ShaderChunk::getShaderSource(#name)

std::map<std::string,IUniform*> mergeUniforms
    (std::vector<std::map<std::string,IUniform*>> vec)
{
    return std::map<std::string,IUniform*>();
}

ShaderLib::lib_t ShaderLib::smLib = {
    {
     "basic",
     {
         mergeUniforms({
                        GET_UNIFORMS_LIB(common),
                        GET_UNIFORMS_LIB(specularmap),
                        GET_UNIFORMS_LIB(envmap),
                        GET_UNIFORMS_LIB(aomap),
                        GET_UNIFORMS_LIB(lightmap),
                        GET_UNIFORMS_LIB(fog)
         }),
         GET_SHADERCHUNK_SOURCE("meshbasic_vert"),
         GET_SHADERCHUNK_SOURCE("meshbasic_frag"),
     }
    },
    {
        "lambert",
        {
         mergeUniforms({
             GET_UNIFORMS_LIB(common),
             GET_UNIFORMS_LIB(specularmap),
             GET_UNIFORMS_LIB(envmap),
             GET_UNIFORMS_LIB(aomap),
             GET_UNIFORMS_LIB(lightmap),
             GET_UNIFORMS_LIB(emissivemap),
             GET_UNIFORMS_LIB(bumpmap),
             GET_UNIFORMS_LIB(normalmap),
             GET_UNIFORMS_LIB(displacementmap),
             GET_UNIFORMS_LIB(fog),
             GET_UNIFORMS_LIB(lights),
             {
              {"emissive",new Uniform<Vector3>(Vector3(0.0,0.0,0.0))}
             },
                        }),
         GET_SHADERCHUNK_SOURCE(meshlambert_vert),
         GET_SHADERCHUNK_SOURCE(meshlambert_frag)
        },
     },

    {
        "phong",
        {
         mergeUniforms({
                        GET_UNIFORMS_LIB(common),
                        GET_UNIFORMS_LIB(specularmap),
                        GET_UNIFORMS_LIB(envmap),
                        GET_UNIFORMS_LIB(aomap),
                        GET_UNIFORMS_LIB(lightmap),
                        GET_UNIFORMS_LIB(emissivemap),
                        GET_UNIFORMS_LIB(bumpmap),
                        GET_UNIFORMS_LIB(normalmap),
                        GET_UNIFORMS_LIB(displacementmap),
                        GET_UNIFORMS_LIB(fog),
                        GET_UNIFORMS_LIB(lights),
                        {
                         {"emissive",new Uniform<Vector3>(Vector3(0.0,0.0,0.0))},
                         {"specular",new Uniform<Vector3>(Vector3(1.0,1.0,1.0)) },
                         {"shininess",new Uniform<float>(30)}
                        }
         }),
         GET_SHADERCHUNK_SOURCE(meshphong_vert),
         GET_SHADERCHUNK_SOURCE(meshphong_frag)
        }
    },
    {
     "standard",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(envmap),
                     GET_UNIFORMS_LIB(aomap),
                     GET_UNIFORMS_LIB(lightmap),
                     GET_UNIFORMS_LIB(emissivemap),
                     GET_UNIFORMS_LIB(bumpmap),
                     GET_UNIFORMS_LIB(normalmap),
                     GET_UNIFORMS_LIB(displacementmap),
                     GET_UNIFORMS_LIB(roughnessmap),
                     GET_UNIFORMS_LIB(metalnessmap),
                     GET_UNIFORMS_LIB(fog),
                     GET_UNIFORMS_LIB(lights),
                     {
                         {"emissive",new Uniform<Vector3>(Vector3(0.0,0.0,0.0))},
                         {"roughness", new Uniform<float>(1.0)},
                         {"metalness", new Uniform<float>(0.0)},
                         {"envMapIntensity",new Uniform<float>(1)} // temporary
                     }
      }),
      GET_SHADERCHUNK_SOURCE(meshphysical_vert),
      GET_SHADERCHUNK_SOURCE(meshphysical_frag)
     }
    },
    {
     "toon",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(aomap),
                     GET_UNIFORMS_LIB(lightmap),
                     GET_UNIFORMS_LIB(emissivemap),
                     GET_UNIFORMS_LIB(bumpmap),
                     GET_UNIFORMS_LIB(normalmap),
                     GET_UNIFORMS_LIB(displacementmap),
                     GET_UNIFORMS_LIB(gradientmap),
                     GET_UNIFORMS_LIB(fog),
                     GET_UNIFORMS_LIB(lights),
                     {
                      {"emissive",new Uniform<Vector3>(Vector3(0,0,0)) }
                     }
      }),
      GET_SHADERCHUNK_SOURCE(meshtoon_vert),
      GET_SHADERCHUNK_SOURCE(meshtoon_frag)
     }
    },
    {
     "matcap",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(bumpmap),
                     GET_UNIFORMS_LIB(normalmap),
                     GET_UNIFORMS_LIB(displacementmap),
                     GET_UNIFORMS_LIB(fog),
                     {
                         {"matcap",new Uniform<float>()} // texture?
                     }
      }),
      GET_SHADERCHUNK_SOURCE(meshmatcap_vert),
      GET_SHADERCHUNK_SOURCE(meshmatcap_frag)
     }
    },
    {
     "points",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(points),
                     GET_UNIFORMS_LIB(fog)
      }),
      GET_SHADERCHUNK_SOURCE(points_vert),
      GET_SHADERCHUNK_SOURCE(points_frag)
     }
    },

    {
     "dashed",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(fog),
                     {
                      {"scale", new Uniform<float>(1) },
                      {"dashSize", new Uniform<float>(1) },
                      {"totalSize", new Uniform<float>(2) }
                     }
      }),
      GET_SHADERCHUNK_SOURCE(linedashed_vert),
      GET_SHADERCHUNK_SOURCE(linedashed_frag)
     }
    },
    {
     "depth",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(displacementmap)
      }),
      GET_SHADERCHUNK_SOURCE(depth_vert),
      GET_SHADERCHUNK_SOURCE(depth_frag)
     }
    },

    {
     "normal",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(bumpmap),
                     GET_UNIFORMS_LIB(normalmap),
                     GET_UNIFORMS_LIB(displacementmap),
                     {
                      {"opacity",new Uniform<float>(1.0)}
                     }
      }),
      GET_SHADERCHUNK_SOURCE(meshnormal_vert),
      GET_SHADERCHUNK_SOURCE(meshnormal_frag)

     }
    },

    {
     "sprite",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(sprite),
                     GET_UNIFORMS_LIB(fog)
      }),
      GET_SHADERCHUNK_SOURCE(sprite_vert),
      GET_SHADERCHUNK_SOURCE(sprite_frag)
     }
    },

    {
     "background",
     {
      {
       {"uvTransform",new Uniform<Matrix3>() },
       {"t2D", new Uniform<float>( /*null*/)},			//TODO: ????
       {"backgroundIntensity",new Uniform<float>(1)}
      },
      GET_SHADERCHUNK_SOURCE(background_vert),
      GET_SHADERCHUNK_SOURCE(background_frag)
     }
    },

    {
     "backgroundCube",
     {
      {
       {"envMap",new Uniform<float>() },		//TODO : texture
       {"flipEnvMap", new Uniform<float>(-1) },
       {"backgroundBlurriness", new Uniform<float>(0) },
       {"backgroundIntensity", new Uniform<float>(1) }
      },
      GET_SHADERCHUNK_SOURCE(backgroundCube_vert),
      GET_SHADERCHUNK_SOURCE(backgroundCube_frag)
     }
    },
    {
     "cube",
     {
      {
       {"tCube", new Uniform<float>() },		//TODO , texture
       {"tFlip", new Uniform<float>(-1)},
       {"opacity", new Uniform<float>(1.0)}
      },
      GET_SHADERCHUNK_SOURCE(cube_vert),
      GET_SHADERCHUNK_SOURCE(cube_frag)
     }
    },
    {
     "equirect",
     {
      {
          {"tEquirect",new Uniform<float>() },	//TODO : texture
      },

      GET_SHADERCHUNK_SOURCE(equirect_vert),
      GET_SHADERCHUNK_SOURCE(equirect_frag)
     }
    },

    {
     "distanceRGBA",
     {
      mergeUniforms({
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(displacementmap),
                     {
                      {"referencePosition", new Uniform<Vector3>(Vector3(0,0,0)) },
                      {"nearDistance", new Uniform<float>(1) },
                      {"farDistance", new Uniform<float>(1000) }
                     }
      }),

      GET_SHADERCHUNK_SOURCE(distanceRGBA_vert),
      GET_SHADERCHUNK_SOURCE(distanceRGBA_frag)
     }
    },
    {
     "shadow",
     {
      mergeUniforms({
          GET_UNIFORMS_LIB(lights),
          GET_UNIFORMS_LIB(fog),
          {
           {"color", new Uniform<Vector3>(Vector3(0,0,0)) },
           {"opacity",new Uniform<float>(1.0)}
          },
                     }),
      GET_SHADERCHUNK_SOURCE(shadow_vert),
      GET_SHADERCHUNK_SOURCE(shadow_frag)

     }
    },
    {
     "physical",
     {
      mergeUniforms({
                     ////////////////////////////////////////
                     //Same as standard.uniforms
                     GET_UNIFORMS_LIB(common),
                     GET_UNIFORMS_LIB(envmap),
                     GET_UNIFORMS_LIB(aomap),
                     GET_UNIFORMS_LIB(lightmap),
                     GET_UNIFORMS_LIB(emissivemap),
                     GET_UNIFORMS_LIB(bumpmap),
                     GET_UNIFORMS_LIB(normalmap),
                     GET_UNIFORMS_LIB(displacementmap),
                     GET_UNIFORMS_LIB(roughnessmap),
                     GET_UNIFORMS_LIB(metalnessmap),
                     GET_UNIFORMS_LIB(fog),
                     GET_UNIFORMS_LIB(lights),
                     {
                         {"emissive",new Uniform<Vector3>(Vector3(0.0,0.0,0.0))},
                         {"roughness", new Uniform<float>(1.0)},
                         {"metalness", new Uniform<float>(0.0)},
                         {"envMapIntensity",new Uniform<float>(1)} // temporary
                     },
                     /////////////////////////////////////////
                     {
                         {"clearcoat", new Uniform<float>(0) },
                         {"clearcoatMap", new Uniform<float>() }, 	//TODO: texture
                         {"clearcoatRoughness", new Uniform<float>(0) },
                         {"clearcoatRoughnessMap", new Uniform<float>() }, 	//TODO: texture
                         {"clearcoatNormalScale", new Uniform<Vector2>(Vector2( 1, 1 )) },
                         {"clearcoatNormalMap", new Uniform<float>() }, 	//TODO: texture
                         {"iridescence", new Uniform<float>(0) },
                         {"iridescenceMap", new Uniform<float>() }, 	//TODO: texture
                         {"iridescenceIOR", new Uniform<float>(1.3) },
                         {"iridescenceThicknessMinimum", new Uniform<float>(100) },
                         {"iridescenceThicknessMaximum", new Uniform<float>(400) },
                         {"iridescenceThicknessMap", new Uniform<float>() }, 	//TODO: texture
                         {"sheen", new Uniform<float>(0) },
                         {"sheenColor", new Uniform<Vector3>(Vector3(0,0,0)) },
                         {"sheenColorMap", new Uniform<float>() }, 	//TODO: texture
                         {"sheenRoughness", new Uniform<float>(1) },
                         {"sheenRoughnessMap", new Uniform<float>() }, 	//TODO: texture
                         {"transmission", new Uniform<float>(0) },
                         {"transmissionMap", new Uniform<float>() }, 	//TODO: texture
                         {"transmissionSamplerSize", new Uniform<Vector2>() },
                         {"transmissionSamplerMap", new Uniform<float>() }, 	//TODO: texture
                         {"thickness", new Uniform<float>() },
                         {"thicknessMap", new Uniform<float>() }, 	//TODO: texture
                         {"attenuationDistance", new Uniform<float>() },
                         {"attenuationColor", new Uniform<Vector3>(Vector3(0,0,0)) },
                         {"specularIntensity", new Uniform<float>(1) },
                         {"specularIntensityMap", new Uniform<float>() }, 	//TODO: texture
                         {"specularColor", new Uniform<Vector3>(Vector3( 1, 1, 1 ))},
                         {"specularColorMap", new Uniform<float>() }, 	//TODO: texture
                     }
      }),
      GET_SHADERCHUNK_SOURCE(meshphysical_vert),
      GET_SHADERCHUNK_SOURCE(meshphysical_frag)
     }
    }

};

ShaderLib::ShaderItem &ShaderLib::getShaderItemByName(const std::string &name)
{
    auto it = smLib.find(name);
    if(it==smLib.end())
    {
        POCELAIN_LOG_ERROR("No shader item named : %s \n",name.c_str());
        abort();
    }
    return it->second;
}

ShaderLib::ShaderLib()
{

}

ShaderLib::~ShaderLib()
{

}

POCELAIN_NAMESPACE_END
